package home.contaduria.domain;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ClientDataOnDemand {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @PersistenceContext
    private EntityManager entityManager;

    private List<Client> data;
    private Random random = new Random();

    public Client getNewTransientClient(int index) {
        Client newClient = new Client();
        setLogin(newClient, index);
        setPassword(newClient, index);
        setEmail(newClient, index);
        setRoles(newClient);
        setState(newClient);
        return newClient;
    }

    public void setLogin(Client client, int index) {
        client.setLogin("login_" + index);
    }

    public void setPassword(Client client, int index) {
        client.setPassword("pwd_" + index);
        client.setConfirmPassword("pwd_" + index);
    }

    public void setEmail(Client client, int index) {
        client.setEmail(index + "_email@mail.com");
    }

    public void setRoles(Client client) {
        Set<AppRole> roles = EnumSet.of(AppRole.USER);
        client.setRoles(roles);
    }

    public void setState(Client client) {
        client.setState(ClientState.ACTIVE);
    }

    public void init() {
        logger.info("Initialize test data with default size");

        data = findClientEntries(0, 10);
        if (data == null)
            throw new IllegalStateException("Find entries implementation for 'Client' illegally returned null");
        if (!data.isEmpty()) {
            logger.info("Initialize test data with existing DB entities");
            return;
        }

        data = new ArrayList<Client>();
        for (int i = 0; i < 10; i++) {
            Client obj = getNewTransientClient(i);
            entityManager.persist(obj);
            entityManager.flush();
            data.add(obj);
        }
        entityManager.flush();
        logger.info("Test data successfully initialized");
    }

    public void init(int size) {
        logger.info("Initialize test data with size {}", size);

        if (size < 1) {
            throw new IllegalArgumentException("Size value should not be less 1. Actual value is " + size);
        }
        data = findClientEntries(0, size);
        if (data == null)
            throw new IllegalStateException("Find entries implementation for 'Client' illegally returned null");
        if (!data.isEmpty() && data.size() >= size) {
            logger.info("Initialize test data with existing DB entities");
            return;
        }

        // data = new ArrayList<Client>();
        for (int i = data.size(); i < size; i++) {
            Client obj = getNewTransientClient(i);
            entityManager.persist(obj);
            entityManager.flush();
            data.add(obj);
        }
        entityManager.flush();
        logger.info("Test data successfully initialized");
    }


    // TODO move this method to ClientDao if required. Try to make it common -
    // add implementation in GenericDaoImpl
    public List<Client> findClientEntries(int firstResult, int maxResults) {
        return entityManager.createQuery("SELECT c FROM Client c", Client.class).setFirstResult(firstResult)
                .setMaxResults(maxResults).getResultList();
    }

    public Client getSpecificClient(int index) {
        if (data == null) {
            throw new IllegalStateException("Method init was not invoked");
        }

        if (index < 0) {
            index = 0;
        }
        if (index > (data.size() - 1)) {
            index = data.size() - 1;
        }
        Client obj = data.get(index);
        return entityManager.find(Client.class, obj.getId());
    }

    public Client getRandomClient() {
        if (data == null) {
            throw new IllegalStateException("Method init was not invoked");
        }

        Client obj = data.get(random.nextInt(data.size()));
        return entityManager.find(Client.class, obj.getId());
    }

}
